using Sustainalytics.Entities;
using Sustainalytics.ESG.Entities;
using Sustainalytics.Synchronization.Validation.Internals;
using Sustainalytics.Synchronization.Validation.Restore;
using Sustainalytics.Synchronization.Validation.ValidationRules.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xunit;
using Xunit.Abstractions;

namespace Sustainalytics.Synchronization.Validation.Tests
{
    public class RegisterTypesTests
    { 
        private static readonly Dictionary<BusinessResearchProduct, List<Type>> ResearchTypeDictionary =
            new Dictionary<BusinessResearchProduct, List<Type>>
                {
                    { BusinessResearchProduct.Comprehensive, new List<Type> { typeof(RPCompanyProfile), typeof(RPIndicatorExtended), typeof(RPCompanyESGComputationResult), typeof(CompanyKeyESGIssue), typeof(Source), typeof(CompanyWeights) } },
                    { BusinessResearchProduct.CorporateGovernance, new List<Type> { typeof(GovernanceIssue), typeof(GovernanceSource), typeof(GovernanceIndicator), typeof(GovernanceCompanyProfile) } },
                };

        private readonly ITestOutputHelper output;

        private readonly Dictionary<string, string> syncConnectionStrings = new Dictionary<string, string>()
                                                                     {
                                                                         { "ClientDW", "mongodb://localhost:27017/ClientDW_B" },
                                                                         { "GovernanceDW", "mongodb://localhost:27017/GovernanceDW_B" },
                                                                     };

        private readonly Dictionary<string, string> currentConnectionStrings= new Dictionary<string, string>()
                                                                     {
                                                                         { "ClientDW", "mongodb://localhost:27017/ClientDW_A" },
                                                                         { "GovernanceDW", "mongodb://localhost:27017/GovernanceDW_A" },
                                                                     };

        public RegisterTypesTests(ITestOutputHelper output)
        {
            this.output = output;
        }

        [Fact]
        public void GetAllTypes()
        {
            var handlersForIHasCompany = new List<Type>();
            var handlersForIEntity = new List<Type>();

            foreach (var type in ResearchTypeDictionary.Keys.SelectMany(researchType => ResearchTypeDictionary[researchType]))
            {
                if (type.ImplementsInterface(typeof(IHasCompanyId)))
                {
                    var handlerType = typeof(HasCompanyIdProfileRestoreHandler<>).MakeGenericType(type);
                    handlersForIHasCompany.Add(handlerType);
                }
                else
                {
                    var handlerType = typeof(EntityProfileRestoreProfileRestoreHandler<>).MakeGenericType(type);
                    handlersForIEntity.Add(handlerType); 
                }
            }

            foreach (var type in handlersForIHasCompany)
            {
                output.WriteLine(type.FullName);
            }

            foreach (var type in handlersForIEntity)
            {
                output.WriteLine(type.FullName);
            }
        }

        [Fact]
        public void GetCollectionsToRegister()
        {
            Func<Dictionary<string, string>, string> getDatabaseName;

            getDatabaseName = x => x["ClientDW"];
            foreach (var type in ResearchTypeDictionary[BusinessResearchProduct.Comprehensive])
            {
                {
                    var method =
                        typeof(ValidationMongoCollectionFactory).GetMethod(
                            "GetCollectionFromDatabase",
                            BindingFlags.Public | BindingFlags.Static).MakeGenericMethod(type);
                     var result = method.Invoke(
                        null,
                        new object[] { currentConnectionStrings, syncConnectionStrings, getDatabaseName, null });

                    output.WriteLine(result.GetType().FullName);
                }
            }
        }
    }
}